package yawning.mew.equipment;

import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import yawning.mew.equipment.RawItem.Property;

public class Item {
	public RawItem mItem;
	public RawItem mSocket1;
	public RawItem mSocket2;
	public RawItem mSocket3;
	public Enchant mEnchant;
	public Enchant mTinker;
	public Property mReforgeFrom;
	public Property mReforgeTo;
	public int mSuffixId;

	private static List<Property> sReforgeableProperties = Arrays.asList(
			Property.SPIRIT,
			Property.EXPERTISE_RATING,
			Property.HIT_RATING,
			Property.CRIT_RATING,
			Property.HASTE_RATING,
			Property.DODGE_RATING,
			Property.PARRY_RATING,
			Property.MASTERY_RATING);

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append(mItem);
		if (mSocket1 != null) sb.append('\n').append("  Gem1: ").append(mSocket1);
		if (mSocket2 != null) sb.append('\n').append("  Gem2: ").append(mSocket2);
		if (mSocket3 != null) sb.append('\n').append("  Gem3: ").append(mSocket3);
		if (mEnchant != null) sb.append('\n').append("  Enchant: ").append(mEnchant);
		if (mTinker != null) sb.append('\n').append("  Tinker: ").append(mTinker);
		if (mReforgeFrom != null) sb.append('\n').append("  Reforged " + (int)(0.4 * mItem.properties.get(mReforgeFrom).intValue()) + " stats from " + mReforgeFrom + " to " + mReforgeTo);
		return sb.toString();
	}

	public boolean addGem(RawItem gem) {
		if (mSocket1 == null) mSocket1 = gem;
		else if (mSocket2 == null) mSocket2 = gem;
		else if (mSocket3 == null) mSocket3 = gem;
		else return false;
		return true;
	}

	public boolean addGem(RawItem gem, int socket) {
		switch (socket) {
		case 0: mSocket1 = gem; break;
		case 1: mSocket2 = gem; break;
		case 2: mSocket3 = gem; break;
		default:
			System.out.println("** mew.equipment.Item: Unrecognized socket id " + socket);
			return false;
		}
		return true;
	}

	public boolean addEnchant(Enchant enchant) {
		if (mEnchant == null) mEnchant = enchant;
		else return false;
		return true;
	}

	public boolean addTinker(Enchant tinker) {
		if (mTinker == null) mTinker = tinker;
		else return false;
		return true;
	}

	public boolean addSuffix(int id) {
		mSuffixId = id;

		// TODO: Actually add stats or something. :(

		return false;
	}

	public Property[] getValidSrcReforges() {
		if (mItem == null) return null;
		List<Property> list = new LinkedList<Property>();
		for (Property p : sReforgeableProperties) {
			if (mItem.properties.containsKey(p)) list.add(p);
		}
		return list.toArray(new Property[0]);
	}

	public Property[] getValidDstReforges() {
		if (mItem == null) return null;
		Set<Property> list = new HashSet<Property>(sReforgeableProperties);
		for (Property p : sReforgeableProperties) {
			if (mItem.properties.containsKey(p)) list.remove(p);
		}
		return list.toArray(new Property[0]);
	}

	public boolean reforge(Property src, Property dst) {
		if (!sReforgeableProperties.contains(src)) return false;
		if (!sReforgeableProperties.contains(dst)) return false;
		if (mItem.properties.containsKey(dst)) return false;
		if (!mItem.properties.containsKey(src)) return false;

		mReforgeFrom = src;
		mReforgeTo = dst;
		return true;
	}

	public int sumProperty(Property p) {
		int total = 0;
		if (mItem.properties.containsKey(p)) total += mItem.properties.get(p).intValue();
		if (mReforgeFrom == p) total -= (int)(0.4 * total);
		if (mReforgeTo == p) total += (int)(0.4 * mItem.properties.get(mReforgeFrom).intValue());
		if (mSocket1 != null && mSocket1.properties.containsKey(p)) total += mSocket1.properties.get(p).intValue();
		if (mSocket2 != null && mSocket2.properties.containsKey(p)) total += mSocket2.properties.get(p).intValue();
		if (mSocket3 != null && mSocket3.properties.containsKey(p)) total += mSocket3.properties.get(p).intValue();
		if (mEnchant != null && mEnchant.properties.containsKey(p)) total += mEnchant.properties.get(p).intValue();

		if (mItem.properties.containsKey(Property.SOCKET_BONUS_STAT)) {
			if (mItem.properties.get(Property.SOCKET_BONUS_STAT).intValue() == p.ordinal()) {
				boolean bonus = true;

				// Only test matches for sockets that come on the item by default.
				switch (mItem.properties.get(Property.NUM_SOCKETS).intValue()){
				case 3: bonus &= testMatch(mSocket3, Property.SOCKET3);
				case 2: bonus &= testMatch(mSocket2, Property.SOCKET2);
				case 1: bonus &= testMatch(mSocket1, Property.SOCKET1);
				}
				if (bonus) total += mItem.properties.get(Property.SOCKET_BONUS_VALUE).intValue();
			}
		}

		return total;
	}

	// Gem colors: 0 = red, 1 = blue, 2 = yellow, 3 = purple, 4 = green, 5 = orange, 6 = meta, 8 = prismatic, 10 = cogwheel
	// Socket colors: 1 = meta, 2 = red, 4 = yellow, 8 = blue, 14 = prismatic, 32 = cogwheel

	private boolean testMatch(RawItem gem, Property slot) {
		if (gem == null) return false;
		if (!mItem.properties.containsKey(slot)) return true;

		int color = gem.properties.get(Property.SUBCLASS).intValue();
		switch (mItem.properties.get(slot).intValue()) {
			case 1: // Meta
				if (color == 6) return true;
				else return false;

			case 2: // red
				if (color == 0 || color == 6 || color == 3 || color == 8) return true;
				else return false;

			case 4: // Yellow
				if (color == 2 || color == 4 || color == 5 || color == 8) return true;
				else return false;

			case 8: // Blue
				if (color == 1 || color == 3 || color == 4 || color == 8) return true;
				else return false;

			case 14: // Prismatic socket
				return true;

			case 32: // Cogwheel socket
				if (color == 10) return true;
				else return false;

			default:
				System.out.println("** mew.equipment.Item: Unrecognized socket type " + mItem.properties.get(slot));
				return true;
		}
	}
}
